package com.star.oauth2.client.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.http.HttpStatus;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.reactive.function.client.WebClient;

import java.util.Arrays;

/**
 * OAuth2客户端安全配置
 * 
 * 配置内容：
 * 1. OAuth2登录配置
 * 2. 客户端注册信息
 * 3. WebClient配置（用于调用资源服务器）
 * 
 * @author star
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    /**
     * 安全过滤器链配置
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            // 关闭CSRF保护，因为我们使用Token进行认证
            .csrf(csrf -> csrf.disable())
            // 配置CORS
            .cors(cors -> cors.configurationSource(corsConfigurationSource()))
            .authorizeHttpRequests(authorize -> authorize
                // 允许访问静态资源和首页
                .requestMatchers("/", "/error", "/webjars/**", "/favicon.ico", "/css/**", "/js/**").permitAll()
                // 允许访问OAuth2回调端点（接收授权码）、token接口和messages页面
                .requestMatchers("/callback", "/auth-success", "/auth-error", "/api/token/**").permitAll()
                // messages页面改为允许匿名访问，由前端JS进行token验证
                .requestMatchers("/messages").permitAll()
                // API请求需要认证，但会返回401而不是重定向
                .requestMatchers("/api/**").authenticated()
                // 其他请求需要认证
                .anyRequest().authenticated()
            )
            // 对API请求返回401而不是重定向
            .exceptionHandling(exceptions -> exceptions
                // 对API请求返回401状态码
                .defaultAuthenticationEntryPointFor(
                    new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED),
                    request -> request.getServletPath().startsWith("/api/")
                )
            )
            // 禁用默认OAuth2登录流程，我们使用自定义的OAuth2回调控制器
            .oauth2Login(oauth2 -> oauth2
                .loginPage("/")
                .defaultSuccessUrl("/", true) // 改为首页，实际我们不会用到这个重定向
                // 禁用OAuth2的默认处理，我们使用自定义控制器处理
                .loginProcessingUrl("/disabled-oauth2-login-process")
            )
            // 配置OAuth2客户端
            .oauth2Client(Customizer.withDefaults())
            // 为API请求配置无状态会话
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            );
        
        return http.build();
    }

    /**
     * CORS配置
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
        configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    /**
     * WebClient配置
     * 用于调用资源服务器API，自动处理OAuth2令牌
     */
    @Bean
    public WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
        ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
                new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
        
        // 默认使用oauth2-client这个客户端注册
        oauth2Client.setDefaultClientRegistrationId("oauth2-client");
        
        return WebClient.builder()
                .baseUrl("http://localhost:8090")
                .apply(oauth2Client.oauth2Configuration())
                .build();
    }

    /**
     * OAuth2客户端管理器
     * 管理OAuth2授权客户端的生命周期
     */
    @Bean
    public OAuth2AuthorizedClientManager authorizedClientManager(
            ClientRegistrationRepository clientRegistrationRepository,
            OAuth2AuthorizedClientRepository authorizedClientRepository) {
        
        // 配置授权提供者（支持授权码和刷新令牌）
        OAuth2AuthorizedClientProvider authorizedClientProvider =
                OAuth2AuthorizedClientProviderBuilder.builder()
                        .authorizationCode()
                        .refreshToken()
                        .build();
        
        DefaultOAuth2AuthorizedClientManager authorizedClientManager =
                new DefaultOAuth2AuthorizedClientManager(
                        clientRegistrationRepository, authorizedClientRepository);
        
        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
        
        return authorizedClientManager;
    }
}